package main

import (
	"time"
	"github.com/gorilla/websocket"
	"global/libs/ws"
	"github.com/ngaut/log"
	"global/constants"
	"encoding/json"
	"global/core"
)

const (
	MaxMessageSize 	= 256
	MaxDeadline		= 4 * time.Hour
)

type HandlerInterface interface {
	Init()
	ReadWriteMessage(handler *Handler, message ws.RequestMessage) error
	Clear()
}

type Handler struct {
	client 		*Client
	ctx 		*core.Context
	conn  		*websocket.Conn
	hi 			HandlerInterface

	response 	chan interface{}
	broke 		chan interface{}
}

func NewHandler(
	client 	*Client,
	ctx  *core.Context,
	conn *websocket.Conn) *Handler {
	h := &Handler{
		client: 		client,
		conn: 			conn,
		ctx: 			ctx,
		response: 		make(chan interface{}, 100),
		broke: 			make(chan interface{}),
	}
	return h
}

func (h *Handler) run(hi HandlerInterface)  {
	h.hi = hi

	h.conn.SetCloseHandler(func(code int, text string) error {
		log.Errorf("Get exit signal, code: %d, text: %s", code, text)
		h.client.exitSignal <- nil
		h.Exit()
		return nil
	})

	// 初始化一次操作
	h.hi.Init()
	h.readMessage()
	h.listening()
}

func (h *Handler) Exit() {
	h.hi.Clear()
}

func (h *Handler) listening() {
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Errorf("Error: %v", r)
			}
		}()
		for {
			select {
			case <-h.broke:
				h.Exit()
				return
			case m := <-h.response:
				if err := h.conn.WriteJSON(m); err != nil {
					log.Errorf("Error: %s", err)
					h.Exit()
					return
				}
			}

		}
	}()
}

// 收到的消息进行转发
func (h *Handler) readMessage()  {
	go func() {
		defer func() {
			// 退出并关闭 socket
			h.broke <- nil
		}()

		h.conn.SetReadDeadline(time.Now().Add(MaxDeadline))
		for {
			var msg ws.RequestMessage
			err := h.conn.ReadJSON(&msg)
			if err != nil {
				if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
					log.Errorf("Error: unexcept close error: %s", err.Error())
				}
				break
			}

			if err = h.dispatch(msg); err != nil {
				log.Errorf("Error: %s", err)
				break
			}
		}
	}()
}

// 消息分发
func (h *Handler) dispatch(message ws.RequestMessage) error {
	var err error
	switch message.MessageId {
	case constants.RequestPing:
		strToBytes := []byte(message.Message)
		err = h.handlerPing(strToBytes)
	default:
		err = h.hi.ReadWriteMessage(h, message)
	}
	return err
}

// 处理 Ping 消息
func (h *Handler) handlerPing(message []byte) error {
	var ping ws.Ping
	err := json.Unmarshal(message, &ping)
	if err != nil {
		return err
	}

	h.response <- ws.WsResponse(&ws.Pong{
		Pong: 		ping.Ping,
	}, constants.RequestPing)

	h.client.Reset()

	return nil
}
